﻿using Microsoft.Extensions.DependencyModel;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.Loader;
using System.Text;

namespace Sven.Core.Libs
{
    public class RuntimeHelper
    {
        // <summary>
        /// 获取项目程序集，排除所有的系统程序集(Microsoft.***、System.***等)、Nuget下载包
        /// </summary>
        /// <returns></returns>
        public static IList<Assembly> GetAllAssemblies()
        {
            var list = new List<Assembly>();
            var deps = DependencyContext.Default;
            var libs = deps.CompileLibraries.Where(lib => !lib.Serviceable && lib.Type != "package");//排除所有的系统程序集、Nuget下载包
            foreach (var lib in libs)
            {
                try
                {
                    var assembly = AssemblyLoadContext.Default.LoadFromAssemblyName(new AssemblyName(lib.Name));
                    list.Add(assembly);
                }
                catch (Exception)
                {
                    // ignored
                }
            }
            return list;
        }

        /// <summary>
        /// 通过程序集的简称获取程序集，不含扩展名
        /// </summary>
        /// <param name="assemblyName"></param>
        /// <returns></returns>
        public static Assembly GetAssembly(string assemblyName)
        {
            return GetAllAssemblies().FirstOrDefault(o => o.FullName.Contains(assemblyName));
        }

        /// <summary>
        /// 通过程序集的全称加载程序集，不含扩展名
        /// </summary>
        /// <param name="assemblyFullName"></param>
        /// <returns></returns>
        public static Assembly GetAssemblyByFullName(string assemblyFullName)
        {
            return AssemblyLoadContext.Default.LoadFromAssemblyName(new AssemblyName(assemblyFullName));
        }

        /// <summary>
        /// 通过程序集全称获取类型列表
        /// </summary>
        /// <param name="assemblyName">程序集的全称不含扩展名</param>
        /// <returns></returns>
        public static IList<Type> GetTypesByAssembly(string assemblyName)
        {
            List<Type> typeList = new List<Type>();

            var assembly = AssemblyLoadContext.Default.LoadFromAssemblyName(new AssemblyName(assemblyName));
            foreach (var typeInfo in assembly.DefinedTypes)
            {
                typeList.Add(typeInfo.AsType());
            }
            return typeList;
        }

        /// <summary>
        /// 通过程序集获取类型列表
        /// </summary>
        /// <param name="assembly"></param>
        /// <returns></returns>
        public static IList<Type> GetTypesByAssembly(Assembly assembly)
        {
            List<Type> typeList = new List<Type>();
            foreach (var typeInfo in assembly.DefinedTypes)
                typeList.Add(typeInfo.AsType());
            return typeList;
        }

        /// <summary>
        /// 获取程序集的所有的类型
        /// </summary>
        /// <returns></returns>
        public static IList<Type> GetAllTypes()
        {
            List<Type> typeList = new List<Type>();
            foreach (var assembly in GetAllAssemblies())
            {
                foreach (var typeInfo in assembly.DefinedTypes)
                {
                    typeList.Add(typeInfo.AsType());
                }
            }
            return typeList;
        }

        /// <summary>
        /// 通过类型名称，接口类型获取实现的类
        /// </summary>
        /// <param name="typeName"></param>
        /// <param name="baseInterfaceType"></param>
        /// <returns></returns>
        public static Type GetImplementType(string typeName, Type baseInterfaceType)
        {
            return GetAllTypes().FirstOrDefault(t =>
             {
                 if (t.Name == typeName && t.GetTypeInfo().GetInterfaces().Any(o => o.Name == baseInterfaceType.Name))
                 {
                     var typeInfo = t.GetTypeInfo();
                     return typeInfo.IsClass && !typeInfo.IsAbstract && !typeInfo.IsGenericType;
                 }
                 return false;
             });
        }

        /// <summary>
        /// 通过程序集获取实现接口类型的类
        /// </summary>
        /// <param name="typeName"></param>
        /// <param name="baseInterfaceType"></param>
        /// <param name="assembly"></param>
        /// <returns></returns>
        public static Type GetImplementType(string typeName, Type baseInterfaceType, Assembly assembly)
        {
            return GetTypesByAssembly(assembly).FirstOrDefault(t =>
             {
                 var typeInfo = t.GetTypeInfo();
                 var faces = typeInfo.GetInterfaces();
                var s = typeInfo.Name == typeName;

                 if (typeInfo.Name == typeName && faces.Any(o => o.Name == baseInterfaceType.Name))
                 {
                     return typeInfo.IsClass && !typeInfo.IsAbstract && !typeInfo.IsGenericType;
                 }
                 return false;
             });
        }

    }
}
